package com.sun.xacml.cond;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;


import org.jdom.Namespace;
import org.jdom.input.DOMBuilder;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.sun.xacml.EvaluationCtx;
import com.sun.xacml.ParsingException;
import com.sun.xacml.attr.AttributeSelector;
import com.sun.xacml.attr.AttributeValue;
import com.sun.xacml.attr.BagAttribute;
import com.sun.xacml.attr.BooleanAttribute;
import com.sun.xacml.attr.GeometryAttribute;
import com.sun.xacml.attr.IntegerAttribute;
import com.sun.xacml.attr.PointAttribute;
import com.sun.xacml.attr.StringAttribute;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;

public class OverlapsFunction extends FunctionBase {
	public static final String identifier = "urn:ogc:def:function:geoxacml:1.0:geometry-overlaps";
	private static URI identifierURI;
	private static String srsName;
	private static Point geometry;
	private static Boolean returnBag = false;
	private static String returnType = "Boolean";
	private static Geometry param1;
	private static Geometry param2;
	private static String geo;
	String xpathVersion;
	// private mapping of standard functions to their argument types
    private static HashMap typeMap;

    /**
     * Static initializer sets up a map of standard function names to their
     * associated datatypes
     */
    static {
        typeMap = new HashMap();
        typeMap.put(identifier, GeometryAttribute.identifier);
    }
    
    /**
     * Returns an <code>EqualFunction</code> that provides the type-equal
     * functionality over the given attribute type. This should be used to
     * create new function instances for any new attribute types, and the
     * resulting object should be put into the <code>FunctionFactory</code>
     * (instances for the standard types are pre-installed in the standard
     * factory).
     * <p>
     * Note that this method has the same affect as invoking the constructor
     * with the same parameters. This method is provided as a convenience,
     * and for symmetry with the bag and set functions.
     *
     * @param functionName the name to use for the function
     * @param argumentType the type to operate on
     *
     * @return a new <code>EqualFunction</code>
     */
    public static OverlapsFunction getEqualInstance(String functionName,
                                                 String argumentType) {
        return new OverlapsFunction(functionName, argumentType);
    }

    /**
     * Creates a new <code>EqualFunction</code> object that supports one
     * of the standard type-equal functions. If you need to create an
     * instance for a custom type, use the <code>getEqualInstance</code>
     * method or the alternate constructor.
     *
     * @param functionName the standard XACML name of the function to be
     *                     handled by this object, including the full namespace
     *
     * @throws IllegalArgumentException if the function isn't standard
     */
    public OverlapsFunction(String functionName) {
        this(functionName, getArgumentType(functionName));
    }

    /**
     * Creates a new <code>EqualFunction</code> object.
     *
     * @param functionName the standard XACML name of the function to be
     *                     handled by this object, including the full namespace
     * @param argumentType the standard XACML name for the type of
     *                     the arguments, inlcuding the full namespace
     */
    public OverlapsFunction(String functionName, String argumentType) {
        super(functionName, 0, argumentType, false, 2,
              BooleanAttribute.identifier, false);
        //System.out.println("2 tham so");
    }

    /**
     * Private helper that returns the type used for the given standard
     * type-equal function.
     */
    private static String getArgumentType(String functionName) {
        String datatype = (String)(typeMap.get(functionName));

        if (datatype == null)
            throw new IllegalArgumentException("not a standard function: " +
                                               functionName);
        
        return datatype;
    }


	public OverlapsFunction(){
		super(identifier, 1, returnType, returnBag);
		System.out.println("getSuppoted");
	}
		
	/* public WithinFunction getInstance(Node root) throws URISyntaxException, ParsingException, ParseException {
		 	System.out.println("getInstance");
	        return new WithinFunction((Element) root, xpathVersion);
	    }*/
	 
	 /**
	     * Returns a <code>Set</code> containing all the function identifiers
	     * supported by this class.
	     *
	     * @return a <code>Set</code> of <code>String</code>s
	     */
	    public static Set getSupportedIdentifiers() {
	        return Collections.unmodifiableSet(typeMap.keySet());
	   }


	    @Override
	    public EvaluationResult evaluate(List inputs, EvaluationCtx context) {

	  
	        // Evaluate the arguments
	        ArrayList<GeometryAttribute> argValues = new ArrayList();
	        EvaluationResult result = evalArgs(inputs, context, argValues);
	        if (result != null)
	        {
	        	//System.out.println("result ! null");
	            return result;
	        }
	        // Now that we have real values, perform the equals operation
	        //System.out.println("argValue[0] " + argValues[0].equals(argValues[1]));
	        //System.out.println("argValue[1] " + argValues[1].getGeometry().getCoordinate());
	        boolean results = false;
	        for(int i=1; i < argValues.size() && argValues.get(i) != null ; i++)
	        {
	        	System.out.println("srsName =" + argValues.get(i).getSrsName() );
	        	if(argValues.get(0).getSrsName().equals(argValues.get(i).getSrsName()))
	        	{
	        		if(argValues.get(i).getGeometry().overlaps(argValues.get(0).getGeometry()))
	        		{
	        			System.out.print("vo day roi");
	        			return EvaluationResult.getInstance(argValues.get(i).getGeometry().overlaps(argValues.get(0).getGeometry()));
	        		}
	        	}
	        }
	        return EvaluationResult.getInstance(results);
	    }
	    
	    /**
	     * Evaluates each of the parameters, in order, filling in the argument
	     * array with the resulting values. If any error occurs, this method
	     * returns the error, otherwise null is returned, signalling that
	     * evaluation was successful for all inputs, and the resulting argument
	     * list can be used.
	     *
	     * @param params a <code>List</code> of <code>Evaluatable</code>
	     *               objects representing the parameters to evaluate
	     * @param context the representation of the request
	     * @param args an array as long as the params <code>List</code> that
	     *             will, on return, contain the <code>AttributeValue</code>s
	     *             generated from evaluating all parameters
	     *
	     * @return <code>null</code> if no errors were encountered, otherwise
	     *         an <code>EvaluationResult</code> representing the error
	     */
	    protected EvaluationResult evalArgs(List params, EvaluationCtx context,
	                                        ArrayList<GeometryAttribute> args) {
	        Iterator it = params.iterator();
	        //int index = 0;
	        //args = new GeometryAttribute

	        while (it.hasNext()) {
	            // get and evaluate the next parameter
	            Evaluatable eval = (Evaluatable)(it.next());
	            EvaluationResult result = eval.evaluate(context);

	            // If there was an error, pass it back...
	            if (result.indeterminate())
	                return result;

	            // ...otherwise save it and keep going
	            //Dua vao dac ta luan van truoc
	            //Gia tri dau vao thu 1 la AttributeValue
	            //Gia tri dau vao thu 2 la AttributeSelector hoac AttributeDesignator
	            if(result.getAttributeValue() instanceof GeometryAttribute)
	            {
	            	args.add((GeometryAttribute) result.getAttributeValue());
	            	System.out.println("result + " + ((GeometryAttribute) result.getAttributeValue()).getGeometry());
	            }
	            else if(result.getAttributeValue() instanceof BagAttribute)
	            {
	            	//Neu tham so dau vao la AttributeSelector thi tra ve cac gia tri
	            	//trong bag vao mang args[]
	            	
	            	BagAttribute bag = (BagAttribute) result.getAttributeValue();
	            	Iterator iterator;
	            	iterator = bag.iterator();
	            	//int bagIndex = 0;
	            	
	            	System.out.println("bagSize " + bag.size());
	            	//GeometryAttribute bagList[] = new GeometryAttribute[bag.size()];
	            	while(iterator.hasNext()){ 
	            		//bagList[bagIndex++].getInstance(params.get(1));
	            		args.add((GeometryAttribute) iterator.next());
	            		
	            }
	            	
	            }
	            //else args[index++] = result.getAttributeValue();
	            
	        }

	        // if no error occurred then we got here, so we return no errors
	        return null;
	    }
	    /**
	     * Kiem tra neu tham so dau vao
	     */
	    public void checkInputs(List inputs) throws IllegalArgumentException {
	        // check that none of the inputs is a bag
	        Object [] list = inputs.toArray();
	        //System.out.println("input list data type" + list[0]);
	        for (int i = 0; i < list.length; i++)
	        {
	        	if(list[i] instanceof AttributeSelector)
	        	{
	        		//System.out.println("input list " + i + list[i]);
	        		if (!((AttributeSelector)(list[i])).evaluatesToBag())
	        			throw new IllegalArgumentException("geometry-equals can't use bags");
	        	}
	        }
	        // if we got here then there were no bags, so ask the other check
	        // method to finish the checking
	        checkInputsNoBag(inputs);
	    }
}
